package level.editor.control.tile;

import gnu.trove.TIntProcedure;

import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Map;
import com.infomatiq.jsi.rtree.RTree;

import level.editor.control.layer.Layer;
import level.editor.control.layer.LayerImage;
import level.editor.control.layer.LayerPainter;
import level.editor.control.main.Main;
import level.model.Addable;
import level.model.StateTileLayer;
import level.model.Tile;
import level.model.utility.StateHandler;

public class TileLayer extends Layer implements TIntProcedure
{

	public TileLayer(StateTileLayer layer)
	{
		super(layer);
		selected = false;
		toDelete = new ArrayList<Integer>();
	}

	public void requestMinimap()
	{
		// SwingUtilities.invokeLater(new Runnable()
		// {
		// public void run()
		// {
		if (getParent() != null)
		{
			((Main) getParent()).updateMinimap(layer.getZOrder(), image);
			Runtime.getRuntime().gc();
		}
		// }
		// });
	}

	public void setSelected(boolean selected)
	{
		this.selected = selected;
	}

	public boolean isSelected()
	{
		return selected;
	}

	public void addRectangle(Addable addable, Point topLeft, int rows,
			int cols, LayerImage image)
	{
		if (addable instanceof Tile)
		{
			LayerPainter.updateImage(this, image);

			for (int x = 0; x < cols; x++)
			{
				for (int y = 0; y < rows; y++)
				{
					Tile tile = (Tile) addable;
					tile.setX((int) (topLeft.getX() + x
							* TileConstants.TILE_SIZE));
					tile.setY((int) (topLeft.getY() + y
							* TileConstants.TILE_SIZE));
					StateHandler.add(layer, addable);
				}
			}
		}
	}

	@Override
	public void debug()
	{
		Map<Integer, Tile> tiles = ((StateTileLayer) layer).getTiles();
		for (int i : tiles.keySet())
		{
			System.out.print("Tile: " + tiles.get(i).getX() + "   "
					+ tiles.get(i).getY() + ", ");
		}
		System.out.println();
	}

	@Override
	public Addable select(Point pt)
	{
		Tile tile = selectSingle(pt);
		return tile;
	}

	@Override
	public ArrayList<Addable> select(Rectangle rectangle)
	{
		ArrayList<Addable> tiles = new ArrayList<Addable>();
		tiles = selectRectangle(new com.infomatiq.jsi.Rectangle(rectangle.x,
				rectangle.y, rectangle.x + rectangle.width, rectangle.y
						+ rectangle.height));

		return tiles;
	}

	@Override
	public boolean execute(int index)
	{
		
//		Map<Integer, Tile> tiles = ((StateTileLayer) layer).getTiles();
//		Tile tile = tiles.get(index);

//		System.out.print(index + ":  ");
//		System.out.println(tile.getX() + " " + tile.getY() + " | "
//				+ (tile.getX() + tile.getW() - 1) + " "
//				+ (tile.getY() + tile.getH() - 1));

		toDelete.add(index);

		return true;
	}

	private Tile selectSingle(Point pt)
	{
		RTree tree = layer.getTree();

		toDelete.clear();
		tree.intersects(
				new com.infomatiq.jsi.Rectangle(pt.x, pt.y, pt.x, pt.y), this);

		return singleClearTree();
	}

	private ArrayList<Addable> selectRectangle(
			com.infomatiq.jsi.Rectangle rectangle)
	{
		RTree tree = layer.getTree();

		toDelete.clear();
		tree.intersects(rectangle, this);

		return rectClearTree();
	}

	// @SuppressWarnings("unused")
	// private Point regularSnapPoint(Point pt)
	// {
	// Point point = new Point(pt);
	// point.x = point.x - (point.x < 0 ? TileConstants.TILE_SIZE : 0);
	// point.y = point.y - (point.y < 0 ? TileConstants.TILE_SIZE : 0);
	//
	// point.x = point.x - point.x % TileConstants.TILE_SIZE;
	// point.y = point.y - point.y % TileConstants.TILE_SIZE;
	//
	// return point;
	// }

	private Tile singleClearTree()
	{
		RTree tree = layer.getTree();
		Map<Integer, Tile> tiles = ((StateTileLayer) layer).getTiles();

		for (Integer i : toDelete)
		{
			Tile tile = tiles.get(i);
			tiles.remove(i);
			tree.delete(
					new com.infomatiq.jsi.Rectangle(tile.getX(), tile.getY(),
							tile.getX() + tile.getW() - 1, tile.getY()
									+ tile.getH() - 1), i);
			return tile;
		}

		return null;
	}

	private ArrayList<Addable> rectClearTree()
	{
		RTree tree = layer.getTree();
		Map<Integer, Tile> tiles = ((StateTileLayer) layer).getTiles();
		ArrayList<Addable> result = (!toDelete.isEmpty() ? new ArrayList<Addable>()
				: null);

		for (Integer i : toDelete)
		{
			Tile tile = tiles.get(i);
			tiles.remove(i);
			tree.delete(
					new com.infomatiq.jsi.Rectangle(tile.getX(), tile.getY(),
							tile.getX() + tile.getW() - 1, tile.getY()
									+ tile.getH() - 1), i);
			result.add(tile);
		}

		return result;
	}

	private boolean selected;
	private ArrayList<Integer> toDelete;
}
